/*
 * Copyright (c) 2021 Talkweb Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "wifi_sta.h"

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "cmsis_os2.h"
#include "lwip/api_shell.h"
#include "lwip/netifapi.h"
#include "wifi_device.h"

int g_wifiState = 0;

/**
 * @brief 打印WifiLinkedInfo信息
 * @param info 需要打印信息的WifiLinkedInfo指针
 */
static void PrintWifiLinkedInfo(WifiLinkedInfo *info) {
    if (!info) return;

    static char macAddress[32] = {0};
    unsigned char *mac = info->bssid;
    snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
             mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

    printf("info: bssid: %s, rssi: %d, connState: %d, reason: %d, ssid: %s\r\n",
           macAddress, info->rssi, info->connState, info->disconnectedReason,
           info->ssid);
}

/**
 * @brief WiFi连接状态改变回调
 * @param state WiFi连接状态，参考WifiEventState
 * @param info WiFi连接信息
 */
static void OnWifiConnectionChanged(int state, WifiLinkedInfo *info) {
    if (!info) return;

    printf("%s %d, state = %d \r\n", __FUNCTION__, __LINE__, state);
    PrintWifiLinkedInfo(info);

    g_wifiState = state;
}

/**
 * @brief WiFi扫描状态改变回调
 * @param state WiFi连接状态，参考WifiEventState
 * @param size
 */
static void OnWifiScanStateChanged(int state, int size) {
    printf("%s %d, state = %X, size = %d\r\n", __FUNCTION__, __LINE__, state,
           size);
}

/**
 * @brief 毫秒级延时
 * @param ms 需要延迟的毫秒数
 */
static void Delay(uint32_t ms) {
    uint32_t usPerTicks = (1000 * 1000) / osKernelGetTickFreq();
    osDelay((ms * 1000) / usPerTicks);
    usleep((ms * 1000) % usPerTicks);
}

int IsWifiConnected(void) {
    if (IsWifiActive()) {
        WifiLinkedInfo wifiLinkedInfo = {0};
        WifiErrorCode wifiErrorCode = GetLinkedInfo(&wifiLinkedInfo);
        if (WIFI_SUCCESS == wifiErrorCode) {
            return WIFI_CONNECTED == wifiLinkedInfo.connState &&
                   wifiLinkedInfo.ipAddress != 0;
        }
    }

    return 0;
}

void WifiConnect(WifiInfo wifiInfo) {
    WifiErrorCode errCode;

    WifiEvent eventListener = {
        .OnWifiConnectionChanged = OnWifiConnectionChanged,
        .OnWifiScanStateChanged = OnWifiScanStateChanged};

    WifiDeviceConfig apConfig = {0};
    memcpy(apConfig.ssid, wifiInfo.ssid, strlen(wifiInfo.ssid));
    memcpy(apConfig.preSharedKey, wifiInfo.password, strlen(wifiInfo.password));
    apConfig.securityType = WIFI_SEC_TYPE_PSK;

    Delay(10);

    errCode = RegisterWifiEvent(&eventListener);
    printf("RegisterWifiEvent errCode: %d\r\n", errCode);

    int networkId = -1;
    //启动WiFi STA模式
    errCode = EnableWifi();
    printf("EnableWifi errCode: %d\r\n", errCode);
    Delay(100);

    errCode = AddDeviceConfig(&apConfig, &networkId);
    printf("AddDeviceConfig errCode: %d\r\n", errCode);

    g_wifiState = 0;
    errCode = ConnectTo(networkId);
    printf("ConnectTo(%d) errCode: %d\r\n", networkId, errCode);

    while (!g_wifiState) {
        Delay(10);
    }
    printf("g_wifiState: %d\r\n", g_wifiState);
    Delay(3000);

    // 联网业务开始
    // 这里是网络业务代码...
    struct netif *iface = netifapi_netif_find("wlan0");
    if (iface) {
        err_t ret = netifapi_dhcp_start(iface);
        printf("netifapi_dhcp_start: %d\r\n", ret);

        Delay(2000);  // 等待DHCP服务分配IP地址

        ret = netifapi_netif_common(iface, dhcp_clients_info_show, NULL);
        printf("netifapi_netif_common: %d\r\n", ret);

        g_wifiState = WIFI_STATE_AVALIABLE;

    }

    printf("The Niobe connect wifi success. \r\n");
}
